--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit b7e15933062ea22563dea40fe8a700b4c05ed1cd
Parents : 24da5de
Author : Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-04-30T11:52:10-05:00
feat(android): update notification handling and UI responsiveness with new audio settings permission and improved back navigation
Credit: thanks to Sergey B (Samara Telegram - Reticulum Самара) for testing and providing solutions.
Changes
4 files changed, 77 insertions(+), 39 deletions(-)
Diff
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index fb0160a3..c3dc9d10 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -11,6 +11,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-feature android:name="android.hardware.microphone" android:required="false" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
@@ -43,7 +44,7 @@
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask"
- android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|density|uiMode|keyboard|keyboardHidden|navigation">
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|density|fontScale|keyboard|keyboardHidden|navigation|uiMode|colorMode|layoutDirection">
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
diff --git a/android/app/src/main/java/com/meshchatx/AndroidNotificationBridge.java b/android/app/src/main/java/com/meshchatx/AndroidNotificationBridge.java
index f7218326..ebaec61c 100644
--- a/android/app/src/main/java/com/meshchatx/AndroidNotificationBridge.java
+++ b/android/app/src/main/java/com/meshchatx/AndroidNotificationBridge.java
@@ -229,6 +229,22 @@ public final class AndroidNotificationBridge {
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
+ int id = NOTIFY_BASE_ID;
+ if (dedupeHex != null && dedupeHex.length() >= 8) {
+ try {
+ id = NOTIFY_BASE_ID
+ + (int) (Long.parseLong(
+ dedupeHex.substring(0, Math.min(8, dedupeHex.length())), 16) & 0x7fff_ffff);
+ } catch (NumberFormatException ignored) {
+ id = NOTIFY_BASE_ID + (dedupeHex.hashCode() & 0x7fff_ffff);
+ }
+ }
+
+ try {
+ nm.cancel(id);
+ } catch (Exception ignored) {
+ }
+
NotificationCompat.Builder b = new NotificationCompat.Builder(ctx, MeshChatApplication.CHANNEL_ID_MESSAGES)
.setSmallIcon(R.drawable.ic_stat_meshchatx)
.setContentTitle(title)
@@ -237,16 +253,9 @@ public final class AndroidNotificationBridge {
.setContentIntent(pi)
.setAutoCancel(true)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
- .setVisibility(NotificationCompat.VISIBILITY_PRIVATE);
-
- int id = NOTIFY_BASE_ID;
- if (dedupeHex != null && dedupeHex.length() >= 8) {
- try {
- id = NOTIFY_BASE_ID + (int) (Long.parseLong(dedupeHex.substring(0, Math.min(8, dedupeHex.length())), 16) & 0x7fff_ffff);
- } catch (NumberFormatException ignored) {
- id = NOTIFY_BASE_ID + (dedupeHex.hashCode() & 0x7fff_ffff);
- }
- }
+ .setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
+ .setDefaults(NotificationCompat.DEFAULT_ALL)
+ .setOnlyAlertOnce(false);
try {
nm.notify(id, b.build());
diff --git a/android/app/src/main/java/com/meshchatx/MainActivity.java b/android/app/src/main/java/com/meshchatx/MainActivity.java
index 9f9acab7..371d3125 100644
--- a/android/app/src/main/java/com/meshchatx/MainActivity.java
+++ b/android/app/src/main/java/com/meshchatx/MainActivity.java
@@ -32,6 +32,7 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.activity.OnBackPressedCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.app.ActivityCompat;
@@ -196,33 +197,35 @@ public class MainActivity extends AppCompatActivity {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
- if (!isStartupRequest(url)) {
- return;
- }
- if (startupRequestHadLoadError) {
+ if (!startupPageLoaded) {
+ if (!isStartupRequest(url)) {
+ return;
+ }
+ if (startupRequestHadLoadError) {
+ return;
+ }
+ startupPageLoaded = true;
+ mainHandler.removeCallbacksAndMessages(null);
+ hideStartupLoadingOverlay();
+ dispatchPendingIntentUri();
+ dispatchCallNotificationAction();
return;
}
- startupPageLoaded = true;
- mainHandler.removeCallbacksAndMessages(null);
- webView.setVisibility(android.view.View.VISIBLE);
- loadingLogo.setVisibility(android.view.View.GONE);
- progressBar.setVisibility(android.view.View.GONE);
- loadingText.setVisibility(android.view.View.GONE);
- errorText.setVisibility(android.view.View.GONE);
- dispatchPendingIntentUri();
- dispatchCallNotificationAction();
+ hideStartupLoadingOverlay();
}
@Override
public void onPageStarted(WebView view, String url, android.graphics.Bitmap favicon) {
super.onPageStarted(view, url, favicon);
- if (isStartupRequest(url)) {
+ if (!startupPageLoaded && isStartupRequest(url)) {
startupRequestHadLoadError = false;
- if (!startupPageLoaded) {
- webView.setVisibility(android.view.View.INVISIBLE);
- }
+ webView.setVisibility(android.view.View.INVISIBLE);
+ progressBar.setVisibility(android.view.View.VISIBLE);
+ return;
+ }
+ if (!startupPageLoaded) {
+ progressBar.setVisibility(android.view.View.VISIBLE);
}
- progressBar.setVisibility(android.view.View.VISIBLE);
}
@Override
@@ -371,6 +374,22 @@ public class MainActivity extends AppCompatActivity {
handleIncomingIntent(getIntent());
consumeCallIntentForPending(getIntent());
+ getOnBackPressedDispatcher().addCallback(
+ this,
+ new OnBackPressedCallback(true) {
+ @Override
+ public void handleOnBackPressed() {
+ if (webView != null && webView.canGoBack()) {
+ webView.goBack();
+ } else {
+ setEnabled(false);
+ MainActivity.this.getOnBackPressedDispatcher().onBackPressed();
+ setEnabled(true);
+ }
+ }
+ }
+ );
+
startMeshChatServer();
scheduleConnectionRetry("Connecting to local server...");
}
@@ -674,6 +693,24 @@ public class MainActivity extends AppCompatActivity {
return sw.toString();
}
+ private void hideStartupLoadingOverlay() {
+ if (webView != null) {
+ webView.setVisibility(android.view.View.VISIBLE);
+ }
+ if (loadingLogo != null) {
+ loadingLogo.setVisibility(android.view.View.GONE);
+ }
+ if (progressBar != null) {
+ progressBar.setVisibility(android.view.View.GONE);
+ }
+ if (loadingText != null) {
+ loadingText.setVisibility(android.view.View.GONE);
+ }
+ if (errorText != null && !backendFailed) {
+ errorText.setVisibility(android.view.View.GONE);
+ }
+ }
+
private void showStartupError(String message) {
runOnUiThread(() -> {
mainHandler.removeCallbacksAndMessages(null);
@@ -718,15 +755,6 @@ public class MainActivity extends AppCompatActivity {
return phase + " (" + connectionAttempts + "/" + MAX_CONNECTION_ATTEMPTS + ")";
}
- @Override
- public void onBackPressed() {
- if (webView.canGoBack()) {
- webView.goBack();
- } else {
- super.onBackPressed();
- }
- }
-
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
diff --git a/android/app/src/main/java/com/meshchatx/MeshChatApplication.java b/android/app/src/main/java/com/meshchatx/MeshChatApplication.java
index 371df98d..9702a4bb 100644
--- a/android/app/src/main/java/com/meshchatx/MeshChatApplication.java
+++ b/android/app/src/main/java/com/meshchatx/MeshChatApplication.java
@@ -51,7 +51,7 @@ public class MeshChatApplication extends PyApplication {
NotificationChannel messages = new NotificationChannel(
CHANNEL_ID_MESSAGES,
getString(R.string.notification_channel_messages_name),
- NotificationManager.IMPORTANCE_DEFAULT
+ NotificationManager.IMPORTANCE_HIGH
);
messages.setDescription(getString(R.string.notification_channel_messages_desc));
nm.createNotificationChannel(messages);
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────